/*
 *
 * The HuntDemo sketch
 *
 */

// Two agents. A hunter and a prey.
HunterAgent hunter;
PreyAgent prey;
// Steering behaviours
// Hunter behaviours
Seek seek;
Pursue pursue;
// Prey behaviours
Flee flee;
Evade evade;
// Are we paused?
boolean pause;
// Is this information panel being displayed?
boolean showInfo;
// Record of information
String filename = "data.txt";
PrintWriter output;
long startDemoTime; // Demo starts
long endDemoTime; // Hunter captured the prey
double captureTime;  // In seconds
int numSimulations = 100;
int simulationNumber = 0;

// Initialisation
void setup() {
  size(1000,600); // Large display window
  pause = false;
  showInfo = true;
  
  // Create the agents
  hunter = new HunterAgent(10, 10, 1, new PVector(width/2+30,height/2));
  prey = new PreyAgent(10, 10, 1, new PVector(width/2-30,height/2));

  // Create a Seek behaviour
  seek = new Seek(hunter, prey);
  // Create pursue behaviour
  pursue = new Pursue(hunter, prey);
  // Create flee behaviour
  flee = new Flee(prey, hunter);
  // Create evade behaviour
  evade = new Evade(prey, hunter);

  // Add the behaviour to the agents
  //hunter.behaviours.add(seek);
  hunter.behaviours.add(pursue);
  prey.behaviours.add(flee);

  hunter.setBehaviour("pursue");
  prey.setBehaviour("flee");

  // Create a new file in the sketch directory
  output = createWriter(filename);

  smooth(); // Anti-aliasing on
  pause = true;
}

// Pick a random point in the display window
PVector randomPoint(float radius) {
  return new PVector(random(radius, width - radius), random(radius, height - radius));
}

// The draw loop                                                     rqwfadsdfs
void draw() {
  // Clear the display
  background(255); 
  
  // Move forward one step in steering simulation
  if (!pause) hunter.update();
  if (!pause) prey.update();

  // Draw the agents
  hunter.draw();
  prey.draw();
  
  // Draw the information panel
  if (showInfo) drawInfoPanel();
}
  
// Draw the information panel!
void drawInfoPanel() {
  pushStyle(); // Push current drawing style onto stack
  fill(0);
  text("1 - toggle display", 10, 20);
  text("2 - toggle annotation", 10, 35);
  text("3 - toggle Hunter Agent behaviour (seek/pursue)", 10, 50);
  text("4 - toggle Prey Agent behaviour (flee/evade)", 10, 65);
  text("Space - play/pause", 10, 80);
  text("-- Hunter Agent parameters (increase key/decrease key) --", 10, 95);
  text("Hunter Agent is using " + hunter.getBehaviour() + " behaviour", 10, 110);
  text("Hunter Mass (q/a) = " + hunter.mass, 10, 125);
  text("Hunter Max. Force (w/s) = " + hunter.maxForce, 10, 140);
  text("Hunter Max. Speed (e/d) = " + hunter.maxSpeed, 10, 155);
  text("-- Prey Agent parameters (increase key/decrease key) --", 10, 170);
  text("Prey Agent is using " + prey.getBehaviour() + " behaviour", 10, 185);
  text("Prey Mass (n/b) = " + prey.mass, 10, 200);
  text("Prey Max. Force (v/m) = " + prey.maxForce, 10, 215);
  text("Prey Max. Speed (j/k) = " + prey.maxSpeed, 10, 230);
  text("Press INTRO to start the simulation (please don't change any parameter while simulating)", 10, 245);
  text("Press ESC to stop and finish the simulation", 10, 260);
  text("Click on a position on the screen to move the pray there", 10, 275);
  if (hunter.getBehaviour().equals("pursue")) {
      text("Hunter pursue k value for tpred formula (p/o) = " + hunter.k, 10, 290);
  }
  if (prey.getBehaviour().equals("evade")) {
     text("Prey evade k value for tpred formula (x/z) = " + prey.k, 10, 305);
  }
  popStyle(); // Retrieve previous drawing style
}


void restartDemo() {
  // Demo finished
  endDemoTime = System.currentTimeMillis();
  captureTime = (endDemoTime - startDemoTime) / 1000.0;
  System.out.println("Capture time (in secs): " + String.format("%.3g", captureTime));
  // Write capture time in file
  output.println(String.format("%.3g", captureTime));
  simulationNumber++;

  if (simulationNumber < numSimulations) {
     // Restart parameters for new demo
     hunter.position = randomPoint(hunter.radius);
     prey.position = randomPoint(prey.radius);
     startDemoTime = System.currentTimeMillis();
     loop();
  }
  else {
     output.flush(); // Writes the remaining data to the file
     output.close(); // Finishes the file
     exit();
  }
}

/*
 * Input handlers
 */

// Mouse clicked, so move the prey
void mouseClicked() {
   PVector newTarget = new PVector(mouseX, mouseY);
   prey.position = newTarget;
   hunter.setTarget(prey);
}

// Key pressed
void keyPressed() {
   if (key == ' ') {
     togglePause();
     
   } else if (key == '1' || key == '!') {
     toggleInfo();
     
   } else if (key == '2' || key == '@') {
     hunter.toggleAnnotate();
     prey.toggleAnnotate();
     
     // Vary the hunter's mass
   } else if (key == 'q' || key == 'Q') {
     hunter.incMass();
   } else if (key == 'a' || key == 'A') {
     hunter.decMass();
     // Vary the hunter's maximum force
   } else if (key == 'w' || key == 'W') {
     hunter.incMaxForce();
   } else if (key == 's' || key == 'S') {
     hunter.decMaxForce();
     // Vary the hunter's maximum speed
   } else if (key == 'e' || key == 'E') {
     hunter.incMaxSpeed();
   } else if (key == 'd' || key == 'D') {
     hunter.decMaxSpeed();

   // Vary the prey's mass
   } else if (key == 'n' || key == 'N') {
     prey.incMass();
   } else if (key == 'b' || key == 'b') {
     prey.decMass();
     // Vary the prey's maximum force
   } else if (key == 'v' || key == 'V') {
     prey.incMaxForce();
   } else if (key == 'm' || key == 'M') {
     prey.decMaxForce();
     // Vary the prey's maximum speed
   } else if (key == 'j' || key == 'J') {
     prey.incMaxSpeed();
   } else if (key == 'k' || key == 'K') {
     prey.decMaxSpeed();
   } else if (key == '3') {
     // Toggle hunter behaviour
     if (hunter.getBehaviour().equals("seek")) {
        // Change to Pursue
        setHunterBehaviour("pursue");
     }
     else if (hunter.getBehaviour().equals("pursue")) {
        // Change to Seek
        setHunterBehaviour("seek");
     }
   }
   else if (key == '4') {
     // Toggle pray behaviour
     if (prey.getBehaviour().equals("flee")) {
        // Change to Evade
        setPreyBehaviour("evade");
     }
     else if (prey.getBehaviour().equals("evade")) {
        // Change to Flee
        setPreyBehaviour("flee");
     }
   }
   else if (key == KeyEvent.VK_ESCAPE)  {
     output.flush(); // Writes the remaining data to the file
     output.close(); // Finishes the file
   }
   else if (key == KeyEvent.VK_ENTER)  {
     // Start the simulation
     output.println("Hunter behaviour: " + hunter.getBehaviour() +
                " ; Pray behaviour: " + prey.getBehaviour());
     startDemoTime = System.currentTimeMillis();
     pause = false;
   } else if (key == 'p' || key == 'p') {
     hunter.incK();
   } else if (key == 'o' || key == 'O') {
     hunter.decK();
   } else if (key == 'x' || key == 'X') {
     prey.incK();
   } else if (key == 'z' || key == 'Z') {
     prey.decK();
   }
}

// Toggle the pause state
void togglePause() {
     if (pause) {
       pause = false;
     } else {
       pause = true;
     }
}

// Toggle the display of the information panel
void toggleInfo() {
     if (showInfo) {
       showInfo = false; 
     } else {
       showInfo = true;
     }
}

void setHunterBehaviour(String behaviour) {
    if (behaviour.equals("seek")) {
        seek = new Seek(hunter, prey);
        hunter.behaviours.clear();
        hunter.behaviours.add(seek);
        hunter.setBehaviour(behaviour);
        prey.setTarget(hunter);
    }
    else if (behaviour.equals("pursue")) {
        pursue = new Pursue(hunter, prey);
        hunter.behaviours.clear();
        hunter.behaviours.add(pursue);
        hunter.setBehaviour(behaviour);
        prey.setTarget(hunter);
    }
}

void setPreyBehaviour(String behaviour) {
     if (behaviour.equals("flee")) {
        flee = new Flee(prey, hunter);
        prey.behaviours.clear();
        prey.behaviours.add(flee);
        prey.setBehaviour(behaviour);
        hunter.setTarget(prey);
     }
     else if (behaviour.equals("evade")) {
        evade = new Evade(prey, hunter);
        prey.behaviours.clear();
        prey.behaviours.add(evade);
        prey.setBehaviour(behaviour);
        hunter.setTarget(prey);
     }
}

